import os
import time

from modules.manage_db import ManageDb
from modules.thread import Thread
from business.pre_upgrade_business import PreUpgradeBusiness
from business.in_upgrade_business import InUpgradeBusiness
from business.after_upgrade_business import AfterUpgradeBusiness


class UpgradeScene(ManageDb):
    def __init__(self, *args, **kwargs):
        super(UpgradeScene, self).__init__(*args, **kwargs)
        self.rollback_times = 2
        self.ftp_root_path = kwargs['ftp_root_path']
        self.ftp_path = kwargs['ftp_path']
        self.git_link = kwargs['git_link']
        self.git_branch = kwargs['git_branch']
        self.scene_name = kwargs['scene_name']
        self.schds = kwargs['schds']

        self.ftp_vmap_path = kwargs['ftp_vmap_path']
        self.up_prefix = 'upgrade_'
        self.di_prefix = 'direct_'
        self.up_db_v = kwargs['upgrade_db_version'].strip().split()
        self.up_ftp_path = kwargs['upgrade_ftp_path'].strip().split()
        self.up_cm_flag = [False if i == 'False' else True for i in
                           kwargs['upgrade_cm_flag'].strip().split()]
        self.label = '~'.join(self.up_db_v)

        self.codehub_pkg_path = '/home/codehub/upgrade'
        self.yat_suite_name = 'upgrade'
        self.db_root_path = '/data'
        self.pkg_root_path = '/opt'
        self.core_path = '/core/upgrade'
        self.db_name = 'tpccdb'
        self.db_user = 'tpccuser'
        self.dolphin_versions = {}
        self.vamp_path = ''
        self.business_info = {'tpcc_path': kwargs['tpcc_path'],
                              'tpcc_user': 'tpccuser',
                              'userpasswd': kwargs['userpasswd'],
                              'db_root_path': kwargs['db_root_path'],
                              'ipaddress': kwargs['ipaddress'],
                              'ipaddress_std1': kwargs['ipaddress_std1'],
                              'up_db_v': self.up_db_v,
                              'ipaddress_std2': kwargs['ipaddress_std2']}
        self.pre_business = PreUpgradeBusiness(**self.business_info)
        self.in_business = InUpgradeBusiness(**self.business_info)
        self.after_business = AfterUpgradeBusiness(**self.business_info)

    def auto_upgrade(self, grey_flag=True, run_sql_flag=False,
                     compare_flag=False):
        """
        升级-提交
        :param grey_flag: 为True时灰度升级，否则为就地升级，默认为True
        :param run_sql_flag: 为True时升级后连跑SQL用例，否则升级后不连跑SQL用例
        :param compare_flag: 为True时执行升级后数据库vs直接安装数据库系统表、权限等对比，否则不执行
        :return: 无
        """
        self.log.info(f'安装低版本{self.up_db_v[0]}用来升级')
        self.install(self.up_prefix, self.up_db_v[0], self.up_ftp_path[0],
                     cm_flag=self.up_cm_flag[0])

        self.log.info('更新数据库用户等信息')
        self.init_data(self.up_prefix, self.di_prefix)
        self.init_base_data()

        self.log.info('检查promethus监控系统是否运行中，若未运行则重新启动')
        self.check_prometheus()
        self.log.info('检查node_exporter是否运行中，若未运行则重新启动')
        self.check_node_exporter()
        self.log.info('启动opengauss-prometheus-exporter')
        self.start_opengauss_exporter(**self.upgrade)

        self.log.info('升级前预置业务')
        pre_res = self.pre_business.pre_upgrade_business_main()

        if compare_flag:
            self.log.info(f'升级前读取tpcc业务数据')
            self.init_compare_data(self.upgrade['db_user'],
                                   'tpccuser',
                                   self.upgrade['pwd'],
                                   self.upgrade['db_name'],
                                   self.upgrade['db_port'])
            self.get_table_data('before_upgrade')

        for i in range(len(self.up_db_v) - 1):
            self.log.info(f'第{i + 1}次升级前检查')
            self.befor_version = self.up_db_v[i]
            self.after_version = self.up_db_v[i + 1]
            self.log.info(f'第{i + 1}次升级前dolphin版本检查')
            res = self.pre_business.get_dolphin_v()
            self.log.info(res)
            if res is not None:
                self.dolphin_versions[res[0]] = res[1]
                self.log.info(self.dolphin_versions)
            self.check_befor_upgrade(cm_flag=self.up_cm_flag[i])

            self.log.info(f'升级到{self.up_db_v[i + 1]}')
            if self.up_cm_flag[i + 1]:
                self.log.info('开始配置xml适配cm')
                self.ins.update_xml_for_cm(**self.hosts)
            self.befor_version = self.up_db_v[i]
            self.after_version = self.up_db_v[i + 1]

            if grey_flag:
                self.log.info('灰度升级过程中执行相关业务、获取断连时间')
                monitor_thread = Thread(self.get_disconnect_time, args=())
                upgrade_thread = Thread(self.do_upgrade,
                                        args=(self.up_ftp_path[i + 1],
                                              '--grey' if grey_flag
                                              else '',
                                              self.up_cm_flag[i]))
                business_thread = Thread(
                    self.in_business.during_upgrade_business_main, args=())
                monitor_thread.setDaemon(True)
                business_thread.setDaemon(True)

                upgrade_thread.start()
                time.sleep(200)
                business_thread.start()
                time.sleep(100)
                monitor_thread.start()
                upgrade_thread.join(1000)
                monitor_thread.join(10)

                upgrade_res = upgrade_thread.get_result()
                self.log.info(f'upgrade_res: {upgrade_res}')
                monitor_res = monitor_thread.get_result()
                self.log.info(f'monitor_res: {monitor_res}')
                business_res = business_thread.get_result()
                self.log.info(f'business_res: {business_res}')
            else:
                self.do_upgrade(self.up_ftp_path[i + 1],
                                '--grey' if grey_flag else '',
                                cm_flag=self.up_cm_flag[i])

            self.after_upgrade(cm_flag=self.up_cm_flag[i + 1])
            self.commit_upgrage()
            self.after_upgrade(cm_flag=self.up_cm_flag[i + 1])

        self.log.info('升级后业务执行')
        self.after_business.after_upgrade_business_main(pre_res=pre_res)

        self.install(self.di_prefix, self.up_db_v[-1],
                     self.up_ftp_path[-1],
                     cm_flag=self.up_cm_flag[-1])

        self.log.info('更新数据库用户等信息')
        self.init_data(self.up_prefix, self.di_prefix)
        self.init_base_data()

        if int(self.up_db_v[-1].replace('.', '')) >= 310 or compare_flag:
            self.log.info('升级vs直接安装对比：B库dolphin插件')
            self.compare_b_mode()

        if int(self.up_db_v[-1].replace('.', '')) < 510:
            self.log.info('直接安装的高版本数据库：加载gs_upgradechk工具')
            self.loading_gs_upgradechk(phase='direct_install')
        self.log.info('获取直接安装数据库的vmap')
        self.vamp_path = self.gs_upgradechk_export(phase='direct_install',
                                                   **self.direct)

        if compare_flag:
            self.log.info(f'升级后读取tpcc业务数据')
            self.get_table_data('after_upgrade')
            self.log.info('升级vs直接安装对比')
            self.log.info('直接安装数据库造数据')
            self.set_tpcc_props(self.direct['ip'], self.direct['db_port'],
                                self.direct['db_name'], 'tpccuser',
                                self.direct['pwd'], self.di_tpcc_pname)
            self.run_tpcc('build', self.di_tpcc_pname)
            self.run_tpcc('run', self.di_tpcc_pname)

            self.log.info('升级vs直接安装对比：系统表&&系统视图')
            self.compare_sys()

            self.log.info('升级vs直接安装对比：元命令')
            self.compare_meta()

            self.log.info('升级vs直接安装对比：权限')
            self.compare_permissions()

            self.log.info('升级vs直接安装对比：业务数据')
            self.cda.compare()

        if run_sql_flag:
            self.log.info('升级后使用yat连跑SQL用例')
            cmd = f'cd /autotest_software/yat-0.10.20/upgrade && ' \
                  f'python3 run_yat.py {self.ftp_root_path} {self.ftp_path} ' \
                  f'{self.up_db_v[-1]} {self.codehub_pkg_path} {self.git_link} ' \
                  f'{self.git_branch} {self.yat_suite_name} ' \
                  f'{self.db_root_path} {self.pkg_root_path} ' \
                  f'{self.core_path} {os.getcwd()} {self.up_prefix} ' \
                  f'{self.db_name} {self.db_user} {self.passwd} ' \
                  f'{self.passwd} {self.passwd} {self.ipaddress} ' \
                  f'{self.ipaddress_std1} {self.ipaddress_std2} ' \
                  f'{" ".join(self.hostnames)} {self.label} {self.scene_name} ' \
                  f'{self.schds}'
            self.log.info(cmd)
            self.sh(cmd)

        if int(self.up_db_v[-1].replace('.', '')) < 510:
            self.log.info('升级后的数据库：加载gs_upgradechk工具')
            self.loading_gs_upgradechk()
        self.log.info('升级后使用gs_upgradechk工具校验元数据')
        self.gs_upgradechk_verify(self.vamp_path, **self.upgrade)

        self.log.info('-----全部执行完成，且断言成功-----')

    def multi_rollback(self, grey_flag=True, force_flag=False,
                       run_sql_flag=False, compare_flag=False):
        """
        升级再回滚场景(可设定回滚次数)，再升级提交
        :param grey_flag: 为True时灰度升级，否则为就地升级，默认为True
        :param force_flag: 为True时强制回滚，否则为普通回滚，默认为False
        :param run_sql_flag: 为True时升级后连跑SQL用例，否则升级后不连跑SQL用例
        :param compare_flag: 为True时执行升级后数据库vs直接安装数据库系统表、权限等对比，否则不执行
        :return: 无
        """
        self.log.info(f'安装低版本{self.up_db_v[0]}用来升级')
        self.install(self.up_prefix, self.up_db_v[0], self.up_ftp_path[0],
                     cm_flag=self.up_cm_flag[0])

        self.log.info('更新数据库用户等信息')
        self.init_data(self.up_prefix, self.di_prefix)
        self.init_base_data()

        self.log.info('检查promethus监控系统是否运行中，若未运行则重新启动')
        self.check_prometheus()
        self.log.info('检查node_exporter是否运行中，若未运行则重新启动')
        self.check_node_exporter()
        self.log.info('启动opengauss-prometheus-exporter')
        self.start_opengauss_exporter(**self.upgrade)

        self.log.info('升级前预置业务数据')
        pre_res = self.pre_business.pre_upgrade_business_main()

        if compare_flag:
            self.log.info(f'升级前读取业务数据')
            self.init_compare_data(self.upgrade['username'],
                                   'tpccuser',
                                   self.upgrade['pwd'],
                                   self.upgrade['db_name'],
                                   self.upgrade['db_port'])
            self.get_table_data('before_upgrade')

        self.log.info('低版本加载gs_upgradechk元数据校验工具')
        if int(self.up_db_v[0].replace('.', '')) < 510:
            self.log.info('低版本数据库：加载gs_upgradechk工具')
            self.loading_gs_upgradechk(phase='before_upgrade')
        self.log.info('获取低版本数据库的vmap')
        self.vamp_path = self.gs_upgradechk_export(phase='before_upgrade',
                                                   **self.upgrade)

        for i in range(len(self.up_db_v) - 1):
            self.log.info(f'第{i + 1}次升级前检查')
            self.befor_version = self.up_db_v[i]
            self.after_version = self.up_db_v[i + 1]
            self.log.info(f'第{i + 1}次升级前dolphin版本检查')
            res = self.pre_business.get_dolphin_v()
            self.log.info(res)
            if res is not None:
                self.dolphin_versions[res[0]] = res[1]
                self.log.info(self.dolphin_versions)

            self.check_befor_upgrade(cm_flag=self.up_cm_flag[i])

            if self.up_db_v[i + 1] != self.up_db_v[-1]:
                self.log.info(f'升级到{self.up_db_v[i + 1]}')
                if self.up_cm_flag[i + 1]:
                    self.log.info('开始配置xml适配cm')
                    self.ins.update_xml_for_cm(**self.hosts)
                self.befor_version = self.up_db_v[i]
                self.after_version = self.up_db_v[i + 1]
                if grey_flag:
                    self.log.info('灰度升级过程中执行相关业务、获取断连时间')
                    monitor_thread = Thread(self.get_disconnect_time, args=())
                    upgrade_thread = Thread(self.do_upgrade,
                                            args=(self.up_ftp_path[i + 1],
                                                  '--grey' if grey_flag
                                                  else '',
                                                  self.up_cm_flag[i]))
                    business_thread = Thread(
                        self.in_business.during_upgrade_business_main, args=())
                    monitor_thread.setDaemon(True)
                    business_thread.setDaemon(True)

                    upgrade_thread.start()
                    time.sleep(200)
                    business_thread.start()
                    time.sleep(100)
                    monitor_thread.start()
                    upgrade_thread.join(1000)
                    monitor_thread.join(10)

                    upgrade_res = upgrade_thread.get_result()
                    self.log.info(f'upgrade_res: {upgrade_res}')
                    monitor_res = monitor_thread.get_result()
                    self.log.info(f'monitor_res: {monitor_res}')
                    business_res = business_thread.get_result()
                    self.log.info(f'business_res: {business_res}')
                else:
                    self.do_upgrade(self.up_ftp_path[i + 1],
                                    '--grey' if grey_flag else '',
                                    cm_flag=self.up_cm_flag[i])

                self.after_upgrade(cm_flag=self.up_cm_flag[i + 1])
                self.commit_upgrage()
                self.after_upgrade(cm_flag=self.up_cm_flag[i + 1])
            else:
                for j in range(self.rollback_times):
                    self.log.info(f'升级到{self.up_db_v[i + 1]}')
                    if self.up_cm_flag[i + 1]:
                        self.log.info('开始配置xml适配cm')
                        self.ins.update_xml_for_cm(**self.hosts)
                    self.befor_version = self.up_db_v[i]
                    self.after_version = self.up_db_v[i + 1]
                    if grey_flag:
                        self.log.info('灰度升级过程中执行相关业务、获取断连时间')
                        monitor_thread = Thread(self.get_disconnect_time,
                                                args=())
                        upgrade_thread = Thread(self.do_upgrade,
                                                args=(self.up_ftp_path[i + 1],
                                                      '--grey' if grey_flag
                                                      else '',
                                                      self.up_cm_flag[i]))
                        business_thread = Thread(
                            self.in_business.during_upgrade_business_main,
                            args=())
                        monitor_thread.setDaemon(True)
                        business_thread.setDaemon(True)

                        upgrade_thread.start()
                        time.sleep(200)
                        business_thread.start()
                        time.sleep(100)
                        monitor_thread.start()
                        upgrade_thread.join(1000)
                        monitor_thread.join(10)

                        upgrade_res = upgrade_thread.get_result()
                        self.log.info(f'upgrade_res: {upgrade_res}')
                        monitor_res = monitor_thread.get_result()
                        self.log.info(f'monitor_res: {monitor_res}')
                        business_res = business_thread.get_result()
                        self.log.info(f'business_res: {business_res}')
                    else:
                        self.do_upgrade(self.up_ftp_path[i + 1],
                                        '--grey' if grey_flag else '',
                                        cm_flag=self.up_cm_flag[i])

                    self.after_upgrade(cm_flag=self.up_cm_flag[i + 1])
                    if j < self.rollback_times - 1:
                        self.log.info('开始回滚')
                        self.rollback('' if not force_flag else '--force',
                                      'Rollback succeeded',
                                      self.up_db_v[-2])

                        self.log.info('升级前vs回滚后：dolphin版本对比')
                        res = self.pre_business.get_dolphin_v()
                        self.log.info(res)
                        if res is not None:
                            if res[0] in self.dolphin_versions:
                                if self.dolphin_versions[res[0]] == res[1]:
                                    self.log.info(
                                        f'版本{res[0]}对应的dolphin版本升级前和回滚后一致')
                                else:
                                    self.log.info(
                                        f'版本{res[0]}对应的dolphin版本升级前和回滚后不一致')
                            else:
                                self.dolphin_versions[res[0]] = res[1]
                        self.log.info(self.dolphin_versions)

                        if int(self.up_db_v[i].replace('.', '')) < 510:
                            self.log.info('回滚后的数据库：加载gs_upgradechk工具')
                            self.loading_gs_upgradechk()
                        self.log.info('回滚后使用gs_upgradechk工具校验元数据')
                        self.gs_upgradechk_verify(self.vamp_path,
                                                  phase='after_rollback',
                                                  **self.upgrade)
                    else:
                        self.log.info('最后再提交升级')
                        self.commit_upgrage()
                        self.after_upgrade(cm_flag=self.up_cm_flag[-1])

        self.log.info('升级后业务执行')
        self.after_business.after_upgrade_business_main(pre_res=pre_res)

        self.log.info(f'直接安装高版本{self.up_db_v[-1]}')
        self.install(self.di_prefix, self.up_db_v[-1],
                     self.up_ftp_path[-1],
                     cm_flag=self.up_cm_flag[-1])

        self.log.info('更新数据库用户等信息')
        self.init_data(self.up_prefix, self.di_prefix)
        self.init_base_data()

        if int(self.up_db_v[-1].replace('.', '')) < 510:
            self.log.info('直接安装的高版本数据库：加载gs_upgradechk工具')
            self.loading_gs_upgradechk(phase='direct_install')
        self.log.info('获取直接安装数据库的vmap')
        self.vamp_path = self.gs_upgradechk_export(phase='direct_install',
                                                   **self.direct)

        if int(self.up_db_v[-1].replace('.', '')) >= 310 or compare_flag:
            self.log.info('升级vs直接安装对比：B库dolphin插件')
            self.compare_b_mode()

        if compare_flag:
            self.log.info(f'升级后读取业务数据')
            self.get_table_data('after_upgrade')
            self.log.info('升级vs直接安装对比')
            self.log.info('直接安装数据库造数据')
            self.set_tpcc_props(self.direct['ip'], self.direct['db_port'],
                                self.direct['db_name'], 'tpccuser',
                                self.direct['pwd'], self.di_tpcc_pname)
            self.run_tpcc('build', self.di_tpcc_pname)
            self.run_tpcc('run', self.di_tpcc_pname)

            self.log.info('升级vs直接安装对比：系统表&&系统视图')
            self.compare_sys()

            self.log.info('升级vs直接安装对比：元命令')
            self.compare_meta()

            self.log.info('升级vs直接安装对比：权限')
            self.compare_permissions()

            self.log.info('升级vs直接安装对比：业务数据')
            self.cda.compare()

        if run_sql_flag:
            self.log.info('升级后使用yat连跑SQL用例')
            cmd = f'cd /autotest_software/yat-0.10.20/upgrade && ' \
                  f'python3 run_yat.py {self.ftp_root_path} {self.ftp_path} ' \
                  f'{self.up_db_v[-1]} {self.codehub_pkg_path} ' \
                  f'{self.git_link} {self.git_branch} {self.yat_suite_name} ' \
                  f'{self.db_root_path} {self.pkg_root_path} ' \
                  f'{self.core_path} {os.getcwd()} {self.up_prefix} ' \
                  f'{self.db_name} {self.db_user} {self.passwd} ' \
                  f'{self.passwd} {self.passwd} {self.ipaddress} ' \
                  f'{self.ipaddress_std1} {self.ipaddress_std2} ' \
                  f'{" ".join(self.hostnames)} {self.label} {self.scene_name} ' \
                  f'{self.schds}'
            self.sh(cmd)

        if int(self.up_db_v[-1].replace('.', '')) < 510:
            self.log.info('升级后的数据库：加载gs_upgradechk工具')
            self.loading_gs_upgradechk()
        self.log.info('升级后使用gs_upgradechk工具校验元数据')
        self.gs_upgradechk_verify(self.vamp_path, **self.upgrade)

        self.log.info('-----全部执行完成，且断言成功-----')
